#include "widget.h"
#include "ui_widget.h"
#include "ui_dialog.h"
#include "command.h"
#include <QThread>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("Modbus TCP Poll");
    this->setFixedSize(WINDOW_WIDTH,WINDOW_HEIGHT);
    this->setWindowIcon(QIcon(WINDOWS_ICO_PATH));
    pic.load(BACK_PATH);

    //mythread = new MyThread;

    Initialize();

    WindowInit();

    connect(ui->link,&QPushButton::clicked,[=](){
        if(ui->EditIP->text().isEmpty())
        {
            ui->EditIP->setText("127.0.0.1");
        }
    });
    //connect(close(),&QPushButton::clicked,this,[](){});

}

void Widget::closeEvent(QCloseEvent *event)
{
    QMessageBox::StandardButton result=QMessageBox::question(this, "确认", "确定要退出程序吗？",
                                                             QMessageBox::Yes|QMessageBox::No |QMessageBox::Cancel,
                                                             QMessageBox::No);

    if (result==QMessageBox::Yes)
    {
        messageLogging();

        event->accept();
    }
    else
        event->ignore();
}

void Widget::WindowInit()
{
    DisplayDataToList();

    QIntValidator *validator3 = new QIntValidator(1,2000,this);
    ui->number->setValidator(validator3);

    //ui->slaveAddr->setPlaceholderText(QString::fromLocal8Bit("1 - 247"));
    ui->startAddr->setPlaceholderText(QString::fromLocal8Bit("0x0000 - 0xFFFF"));
    QIntValidator *validator2 = new QIntValidator(0,65535,this);
    ui->startAddr->setValidator(validator2);
    //ui->number->setPlaceholderText(QString::fromLocal8Bit("not more than startAddr max - slaveAddr"));

    //    QIntValidator *pIntValidator = new QIntValidator(this);
    //    pIntValidator->setRange(1, 2000);

    //    ui->number->setValidator(pIntValidator);
    connect(ui->slaveAddr,&QLineEdit::textEdited,[=](){
        if(ui->slaveAddr->text().toInt()<1||ui->slaveAddr->text().toInt()>127)
        {
            ui->slaveAddr->clear();
            QMessageBox::critical(this,"提示","从机地址超出范围");
        }
    });

    connect(ui->coilSearchBtn,&QPushButton::clicked,[=](){
        int coilIndex = ui->coilLineEdit->text().toInt(nullptr,10);
        //获取搜索位置的指针
        QTableWidgetItem *coilItem = ui->coilTable->item(0,coilIndex);
        ui->coilTable->setCurrentItem(coilItem);
        //滚动到指向位置
        ui->coilTable->scrollToItem(coilItem,QAbstractItemView::PositionAtCenter);
    });
    connect(ui->registerSearchBtn,&QPushButton::clicked,[=](){
        int coilIndex = (ui->registerLineEdit->text().toInt(nullptr,10));
        //获取搜索位置的指针
        QTableWidgetItem *coilItem = ui->registerTable->item(0,coilIndex);
        ui->registerTable->setCurrentItem(coilItem);
        //滚动到指向位置
        ui->registerTable->scrollToItem(coilItem,QAbstractItemView::PositionAtCenter);
    });

    connect(ui->startAddr,&QLineEdit::textChanged,[=](){
        if(ui->startAddr->text().toInt()+ui->number->text().toInt() > 65536)
        {
            QMessageBox::warning(this,"提示","请检查起始地址和数量是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
            ui->startAddr->clear();
        }

    });
    connect(ui->number,&QLineEdit::textChanged,[=](){
        if(ui->startAddr->text().toInt()+ui->number->text().toInt() > 65536)
        {
            QMessageBox::warning(this,"提示","请检查起始地址和数量是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
            ui->number->clear();
        }
        if(ui->number->text()=='0')
        {
            ui->number->clear();
            QMessageBox::warning(this,"提示","请检查数量是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
        }

        if((ui->functionCodeBox->currentText().toInt(nullptr,16)==1&&(ui->number->text().toInt()>2000))\
                ||(ui->functionCodeBox->currentText().toInt(nullptr,16)==3&&(ui->number->text().toInt()>125))\
                ||(ui->functionCodeBox->currentText().toInt(nullptr,16)==15&&(ui->number->text().toInt()>1968))
                ||(ui->functionCodeBox->currentText().toInt(nullptr,16)==16&&(ui->number->text().toInt()>123)))
        {
            ui->number->clear();
            QMessageBox::warning(this,"提示","请检查数量是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
        }
    });

    connect(ui->functionCodeBox,static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),[=](){
        int FuncCodeNumber;
        FuncCodeNumber = ui->functionCodeBox->currentText().toInt(nullptr,16);

        switch(FuncCodeNumber)
        {
        case 0x01:
            //设置0x01背景提示
            ui->number->setPlaceholderText("1 - 2000");
            break;
        case 0x03:
            //设置0x03背景提示
            ui->number->setPlaceholderText("1 - 125");

            break;
        case 0x0f:
            //设置0x0f背景提示
            ui->number->setPlaceholderText("1 - 1968");
            break;
        case 0x10:
            //设置0x10背景提示
            ui->number->setPlaceholderText("1 - 123");
            break;
        }
    });


    QPalette pe;
    pe.setColor(QPalette::WindowText,Qt::white);
    ui->label->setPalette(pe);
    ui->label_2->setPalette(pe);
    ui->label_3->setPalette(pe);
    ui->groupBox->setPalette(pe);
    ui->label_4->setPalette(pe);
    ui->label_5->setPalette(pe);
    ui->label_6->setPalette(pe);
    ui->label_7->setPalette(pe);

}

void Widget::tableItemClicked(int row, int column)
{
    /* do some stuff with item */

    QTableWidgetItem *item = new QTableWidgetItem;
    item = ui->coilTable->item(row,column);
    //    qDebug()<<"row :"<<row<<"  column:"<<column;
    if(TcpConnectIdentifier){
        if(item->text() == "ON")
        {
            ui->coilTable->setItem(row,column,new QTableWidgetItem(QString("OFF")));
            settings->setValue("Section" + QString::number(column) + "/coil",0);
            ui->coilTable->item(1,column)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
            res = "0";
        }
        else if (item->text() == "OFF")
        {
            ui->coilTable->setItem(row,column,new QTableWidgetItem(QString("ON")));
            settings->setValue("Section" + QString::number(column) + "/coil",1);
            ui->coilTable->item(1,column)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
            res = "1";
        }

        //        QString readData = settings->value("Section" + QString::number(row) + "/coil").toString();

        on_requestBtn_clicked(2,column);

    }
    else {
        QMessageBox::warning(this,"错误","未连接到服务器!",QMessageBox::Ok);
    }
}

Widget::~Widget()
{
    delete ui;
}

void Widget::Initialize()
{

    //QFile file("../Modbus-TCP-master/log.txt");

    settings = new QSettings("../Modbus-TCP-master/Data/Data.ini",QSettings::IniFormat);

    TCPSocket = new QTcpSocket();
    this->isconnection=false;
    ui->slot_disconnect->setEnabled(false);

    //在线圈表取反单个线圈
    connect(ui->coilTable, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(tableItemClicked(int,int)));
    //成功连接服务器的connected()信号连接到slot_connected() (注意：不是connect()信号)
    connect(TCPSocket,SIGNAL(connected()),this,SLOT(slot_connected()));
    //发送按钮的clicked()信号连接到slot_sendmessage()
    connect(ui->pushButton_send,SIGNAL(clicked()),this,SLOT(slot_sendmessage()));
    //有新数据到达时的readyread()信号连接到slot_recvmessage()
    connect(TCPSocket,SIGNAL(readyRead()),this,SLOT(slot_recvmessage()));
    //与服务器断开连接的disconnected()信号连接到slot_disconnect()
    connect(TCPSocket,SIGNAL(disconnected()),this,SLOT(slot_disconnect()));

    // connect(ui->messageEdit,SIGNAL(textChanged()),this,SLOT(messageLogging()));

    //connect(ui->viewLog,SIGNAL(clicked()),this,SLOT(on_viewLog_clicked()));
    //connect(ui->requestBtn,SIGNAL(clicked()),this,SLOT(on_requestbtn_clicked(ui->functionCodeBox->currentIndex())));
    connect(ui->requestBtn,&QPushButton::clicked,[=](){
        on_requestBtn_clicked(ui->functionCodeBox->currentIndex(),0);
    });

    ui->slaveAddr->setPlaceholderText("1-247");
    QIntValidator *validator = new QIntValidator(1,247,this);
    ui->slaveAddr->setValidator(validator);

    ui->number->setPlaceholderText("1-2000");
    //    QIntValidator *validator1 = new QIntValidator(1,247,this);
    //    ui->number->setValidator(validator1);


}

//TCP主站请求报文函数
void Widget::on_requestBtn_clicked(int functionCodeBox,int local)
{

    if( TcpConnectIdentifier == false)
    {
        timeInformationPrint();
        ui->messageEdit->append("未连接从站!");
        return;
    }
    //判断功能码
    switch(functionCodeBox)
    {
    case 0:
    {
        //读输出线圈0x01和读输出寄存器0x03请求报文处理函数
        readCoilAndRegisterInfo();
        break;
    }
    case 1:
    {
        //读输出线圈0x01和读输出寄存器0x03请求报文处理函数
        readCoilAndRegisterInfo();
        break;
    }
    case 2:
    {
        //写多个输出线圈0x0F和写多个输出寄存器0x10请求报处理函数
        writeCoilsAndRegisters(local);
        break;
    }
    case 3:
    {
        //写多个输出线圈0x0F和写多个输出寄存器0x10请求报处理函数
        writeCoilsAndRegisters(0);
        break;
    }
    }

    for(resendNumber = 0; resendNumber < RESEND_MAX; resendNumber++)
    {
        //使主线程先处理主界面刷新，避免假死
        QApplication::processEvents();
        if(!TCPSocket->waitForReadyRead(TIMEOUTLENGTH))
        {
            //使用TCP向目标从站重新传输请求报文
            TCPSocket->write(requestMessageArray);
            ui->messageEdit->append("从站无响应！");
            ui->messageEdit->append("已向目标从站第"
                                    + QString::number(resendNumber + 1)
                                    + "次重新发送报文");
        }
        else
        {
            //设置TCP请求报文发送状态为离线
            TCPSendIdentifier = false;
            return;
        }
    }

    //重传次数费完
    //显示错误
    timeInformationPrint();
    ui->messageEdit->append("重传无效！无法收到目标从站的响应！");
    //设置TCP请求报文发送状态为离线
    TCPSendIdentifier = false;
    //清空请求报文数组
    requestMessageArray.clear();

    return;
}

//读寄存器/线圈信息
void Widget::readCoilAndRegisterInfo()//RequestMessage0x010x03()
{
    MessageBasicInformation  MessageBasicInfo;
    structInitialize(&MessageBasicInfo);
    //读输出线圈0x01和读输出寄存器0x03请求报文构建函数
    requestMessageArray = RequestMessageStructureRead(&MessageBasicInfo);

    //判断当前TCP连接状态
    if(TcpConnectIdentifier == true)
    {
        //使用TCP向目标从站传输请求报文
        TCPSocket->write(requestMessageArray);

        //消息框显示发送成功的请求报文
        QString message;
        for(int i = 0; i < requestMessageArray.size(); i++)
        {
            message += QString("%1").arg(quint8(requestMessageArray.at(i)),2,16,QLatin1Char('0'));
            message += " ";
        }
        timeInformationPrint();

        ui->messageEdit->append("请求报文发送成功！ 报文为：" + message);

        //设置TCP请求报文发送状态为在线
        TCPSendIdentifier = true;
    }
    else
    {
        //连接失败，清空请求报文数组，需要重新操作
        requestMessageArray.clear();
        timeInformationPrint();

        ui->messageEdit->append("服务器连接断开，请重新操作！");

        //设置TCP请求报文发送状态为离线
        TCPSendIdentifier = false;
    }

}

//0x01/0x03报文构建函数
QByteArray Widget::RequestMessageStructureRead(MessageBasicInformation *structPtr)
{
    QByteArray requestMess;
    //设置请求报文数组大小为12，即该报文长度为12字节
    requestMess.resize(TCP_REQUEST_MESSAGE_LENGTH);

    /***********************************将数据放入报文数组***********************************/
    //事务元标识符：2字节
    requestMess[0] = structPtr->transactionIdenti >> 8;
    requestMess[1] = structPtr->transactionIdenti & 0xff;
    //协议标识符：2字节
    requestMess[2] = structPtr->protocolIdenti >> 8;
    requestMess[3] = structPtr->protocolIdenti & 0x0ff;
    //长度标识符：2字节
    requestMess[4] = structPtr->length >> 8;
    requestMess[5] = structPtr->length & 0x0ff;
    //单元标识符：1字节
    requestMess[6] = structPtr->slaveAddr;
    //功能码：1字节
    requestMess[7] = structPtr->funcCode;
    //起始地址：2字节
    requestMess[8] = structPtr->beginAddr >> 8;
    requestMess[9] = structPtr->beginAddr & 0x0ff;
    //数量：2字节
    requestMess[10] = structPtr->num >> 8;
    requestMess[11] = structPtr->num & 0x0ff;

    return requestMess;
}

//临时结构体初始化
void Widget::TemporaryStructInitialize(MessageBasicInformation *structPtr,int loacl)
{
    //事务元标识符赋值
    structPtr->transactionIdenti = quint16(1);
    //协议标识符，ModBus协议标识符为0
    structPtr->protocolIdenti = quint16(0);
    //从站地址
    structPtr->slaveAddr = quint16(ui->slaveAddr->text().toInt());
    //起始地址赋值
    structPtr->beginAddr = quint16(loacl);
    //数量赋值
    structPtr->num = 1;
    //长度
    structPtr->length = 6;

    structPtr->funcCode = quint8(15);

}

//结构体初始化函数
void Widget::structInitialize(MessageBasicInformation *structPtr)
{
    //事务元标识符赋值
    structPtr->transactionIdenti = quint16(1);
    //协议标识符，ModBus协议标识符为0
    structPtr->protocolIdenti = quint16(0);
    //从站地址
    structPtr->slaveAddr = quint16(ui->slaveAddr->text().toInt());
    //起始地址赋值
    structPtr->beginAddr = ui->startAddr->text().toUShort();
    //数量赋值
    structPtr->num = ui->number->text().toUShort();
    //长度
    structPtr->length = 6;

    //功能码赋值
    switch(ui->functionCodeBox->currentIndex())
    {
    case 0:
        structPtr->funcCode = quint8(1);
        break;
    case 1:
        structPtr->funcCode = quint8(3);
        break;
    case 2:
        structPtr->funcCode = quint8(15);
        break;
    case 3:
        structPtr->funcCode = quint8(16);
        break;
    }
}
//消息日志保存
void Widget::messageLogging()
{
    //    QFile file("../Modbus-TCP-master/log.txt");
    //    if(!file.exists())
    //    {
    //        file.open(QIODevice::WriteOnly);
    //            file.close();

    //    }
    //    file.write(ui->messageEdit->toPlainText().toUtf8().data());
    //    //消息分块
    //    file.write("\n\n");

    //    file.close();
    if(QFile::exists("./log.txt"))
    {
        QFile file("./log.txt");
        file.open(QFileDevice::Append);
        file.write(ui->messageEdit->toPlainText().toUtf8().data());
        //消息分块
        file.write("\n\n");
        file.close();
        return ;
    }

    QFile file1("./log.txt");

    if(file1.open(QIODevice::WriteOnly))
    {
        QFile file("./log.txt");
        file.open(QFileDevice::Append);
        file.write(ui->messageEdit->toPlainText().toUtf8().data());
        //消息分块
        file.write("\n\n");
        file.close();
        return;
    }
    file1.close();

}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawPixmap(0,0,pic);
}

void Widget::DisplayDataToList()
{
    QString readData;
    ui->coilTable->setRowCount(2);
    ui->coilTable->setColumnCount(MAX_NUMBER+1);
    ui->registerTable->setRowCount(2);
    ui->registerTable->setColumnCount(MAX_NUMBER+1);

    for(int i = 0;i<MAX_NUMBER+1 ;i++)
    {
        QString addr =  "0x" + QString("%1").arg(i,4,16,QLatin1Char('0'));

        ui->coilTable->setItem(0,i,new QTableWidgetItem(QString(addr)));
        readData = settings->value("Section" + QString::number(i+1) + "/coil").toString();
        readData=="1"?readData="ON":readData="OFF";
        ui->coilTable->setItem(1,i,new QTableWidgetItem(QString(readData)));

        ui->registerTable->setItem(0,i, new QTableWidgetItem(QString(addr)));
        readData = settings->value("Section" + QString::number(i+1) + "/regi").toString();
        ui->registerTable->setItem(1,i,new QTableWidgetItem(QString(readData)));

        ui->coilTable->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        ui->coilTable->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        ui->registerTable->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        ui->registerTable->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);

    }
    ui->coilTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
    //ui->coilTable->item(1,i)->setBackground(const QBrush &brush);
}

void Widget::on_link_clicked()
{
    QString IP= ui->EditIP->text();
    qDebug() << IP ;
    int Port = ui->EditPort->text().toInt();
    //终止之前的连接，重置套接字
    //TCPSocket->abort();

    //给定IP和端口号，连接服务器
    TCPSocket->connectToHost(QHostAddress(IP), quint16(Port));
    this->isconnection = TCPSocket->waitForConnected();
    this->ui->link->isFlat();
}

void Widget::slot_connected()
{
    this->isconnection=true;
    ui->label_3->setText("已连接从站");
    ui->slot_disconnect->setEnabled(true);
    ui->link->setEnabled(false);
    TcpConnectIdentifier = true;


    IPAddr = TCPSocket->peerAddress().toString();
    port = int(TCPSocket->peerPort());

    timeInformationPrint();
    //消息窗口显示信息

    QString sendMessage = tr("从站端连接成功!") + tr(" \n ") \
            + tr("从站IP为 : ")+ tr(IPAddr.toUtf8()) + tr(" ") + tr("   \n") ;
    ui->messageEdit->append(sendMessage);

    QMessageBox::information(this, "Modbus TCP", "从站端连接成功!");
}

void Widget::slot_sendmessage()
{
    if(this->isconnection)
    {
        QString sendMessage = ui->lineEdit->text(); //从单行文本框获得要发送消息
        if(!sendMessage.isEmpty())
        {
            //发送消息到服务器
            this->TCPSocket->write(sendMessage.toLocal8Bit());

            //本地显示发送的消息
            QString localDispalyMessage = tr("send to server: ") +"[" \
                    + QDateTime::currentDateTime().toString(" yyyy-M-dd hh:mm:ss") + "]" + tr("\n")
                    + sendMessage ;
            ui->messageEdit->append(localDispalyMessage);
        }
        else
            QMessageBox::warning(this,"错误","消息不能为空!",QMessageBox::Ok);
    }
    else
        QMessageBox::warning(this,"错误","未连接到服务器!",QMessageBox::Ok);

    ui->lineEdit->clear();
}

void Widget::slot_recvmessage()
{
    //QMessageBox::information(this, "Modbus TCP", "有新消息！");
    //接收来自服务器的消息
    QByteArray byteArray = this->TCPSocket->readAll();
    //QString recvMessage = tr("recv from server: ") + byteArray + QDateTime::currentDateTime().toString(" yyyy-M-dd hh:mm:ss\n") + tr("\n");
    //ui->messageEdit->append(recvMessage);
    //QByteArray bufferArray = TCPSocket->readAll();
    messageAnalysis(byteArray);
    messageLogging();

}

void Widget::slot_disconnect()
{
    if(TCPSocket != nullptr&&this->isconnection)
    {
        this->isconnection=false;
        ui->messageEdit->append("连接断开!");
        TCPSocket->disconnectFromHost();
        QMessageBox::information(this, "Modbus TCP", "断开与从站的连接！");
        ui->slot_disconnect->setEnabled(false);
        ui->link->setEnabled(true);
        ui->label_3->setText("未连接从站");
        //  TCPSocket->close(); //关闭客户端
        //  TCPSocket->deleteLater();//deletelater的原理是 QObject::deleteLater()并没有将对象立即销毁，而是向主消息循环发送了一个event，下一次主消息循环收到这个event之后才会销毁对象。
    }
}

void Widget::on_pushButton_2_clicked()
{
    ui->messageEdit->clear();
}

void Widget::on_slot_disconnect_clicked()
{
    slot_disconnect();
    //   TCPSocket = new QTcpSocket();
}

void Widget::on_pushButton_3_clicked()
{
    this->close();
}


void Widget::on_viewLog_clicked()
{
    QFile file("../Modbus-TCP-master/log.txt");
    //    if(!file.open(QFile::ReadOnly|QFile::Text))
    //    {
    //        QMessageBox::warning(this,tr("Error"),tr("read file error:&1").arg(file.errorString()));
    //        return;
    //    }
    //    QTextStream in(&file);
    //    QApplication::setOverrideCursor(Qt::WaitCursor);


    file.open(QFileDevice::ReadOnly);

    //读取文件
    QByteArray array;
    array = file.readAll();

    dialog = new Dialog(this);
    dialog->setModal(false);

    dialog->ui->textEdit->setText(array);
    //dialog->ui->textEdit->setPlainText(in.readAll().toUtf8());

    dialog->ui->textEdit->moveCursor(QTextCursor::End);

    QApplication::restoreOverrideCursor();
    dialog->show();
}

//解析响应报文
bool Widget::messageAnalysis(QByteArray MessageArray)
{
    bool analysisResult;
    //初始化报文字符串
    QString readMessage;

    //将十六进制数据转化成字符串
    readMessage = ByteArrayToString(MessageArray, MessageArray.size(), 1);
    //判断当前主站状态，若是等待消息状态则显示消息，否则提示不是需要的消息
    if(TCPSendIdentifier == true)
    {
        //显示响应报文
        ShowResponseMessage(readMessage);
    }
    else
    {
        //时间
        timeInformationPrint();
        //消息窗口显示信息
        ui->messageEdit->append("当前主站没有需要回复的请求！");
        return false;
    }

    //报文合法性判断
    analysisResult = MessageLegalJudge(MessageArray, requestMessageArray);
    if(analysisResult == false)
    {
        return false;
    }

    //处理匹配的正常响应码
    switch(MessageArray.at(7))
    {
    case 1:
    {
        //0X01功能码报文处理函数
        analysisResult = FuncCodeProcess0X01(MessageArray, requestMessageArray);
        break;
    }

    case 3:
    {
        //0X03功能码报文处理函数
        analysisResult = FuncCodeProcess0X03(MessageArray, requestMessageArray);
        break;
    }

    case 15:
    {
        //0X0f功能码报文处理函数
        analysisResult = FuncCodeProcess0X0F(MessageArray, requestMessageArray);
        break;
    }

    case 16:
    {
        //0X10功能码报文处理函数
        analysisResult = FuncCodeProcess0X10(MessageArray, requestMessageArray);
        break;
    }
    }

    if(analysisResult == true)
    {
        //清空请求报文数组
        requestMessageArray.clear();
    }

    return analysisResult;
}

//显示响应报文函数
void Widget::ShowResponseMessage(QString Message)
{
    //显示收到的报文
    //时间
    timeInformationPrint();
    //消息窗口显示信息
    ui->messageEdit->append("收到来自IP地址："
                            + IPAddr
                            + " 端口号："
                            + QString::number(port)
                            + "的消息："
                            + '\n'
                            + Message);
}

//时间信息打印
void Widget::timeInformationPrint()
{
    ui->messageEdit->append("");
    ui->messageEdit->append("[" + QDateTime::currentDateTime().toString("yyyy-M-dd hh:mm:ss") + "]");
}

//0x0F/0x10请求报文处理函数
void Widget::writeCoilsAndRegisters(int local)
{
    //初始化结构体
    MessageBasicInformation  MessageBasicInfo;

    if(local == 0){structInitialize(&MessageBasicInfo);
    }
    else {
        TemporaryStructInitialize(&MessageBasicInfo,local);
    }
    //初始化输入字节数组
    QByteArray byteArray;
    //根据功能码的不同进行不同的用户输入处理
    if(MessageBasicInfo.funcCode == 15)
    {
        //获取用户线圈输入，返回字节数组
        if(local == 0)
            byteArray = coilsInputProcess();
        else {
            byteArray = TemporarycoilsProcess(res);
        }
    }
    else
    {
        //获取用户寄存器输入，返回字节数组
        byteArray = registersInputProcess();
    }

    //写多个输出线圈0x0F和写多个输出寄存器0x10请求报构建函数
    requestMessageArray = RequestMessageStructureWrite(&MessageBasicInfo, byteArray);
    //发送请求报文
    TCPRequestMessageSend();
}

//写多个输出线圈0x0F和写多个输出寄存器0x10请求报构建函数
QByteArray Widget::RequestMessageStructureWrite(MessageBasicInformation *structPtr, QByteArray byteArr)
{
    quint8 numOfByte = quint8(byteArr.size());
    quint16 length = structPtr->length + numOfByte + 1;
    QByteArray requestMess;
    //设置请求报文数组大小
    requestMess.resize(TCP_REQUEST_MESSAGE_LENGTH + 1 + numOfByte);

    //事务元标识符：2字节
    requestMess[0] = structPtr->transactionIdenti >> 8;
    requestMess[1] = structPtr->transactionIdenti & 0xff;
    //协议标识符：2字节
    requestMess[2] = structPtr->protocolIdenti >> 8;
    requestMess[3] = structPtr->protocolIdenti & 0x0ff;
    //长度标识符：2字节
    requestMess[4] = length >> 8;
    requestMess[5] = length & 0x0ff;
    //单元标识符：1字节
    requestMess[6] = structPtr->slaveAddr;
    //功能码：1字节
    requestMess[7] = structPtr->funcCode;
    //起始地址：2字节
    requestMess[8] = structPtr->beginAddr >> 8;
    requestMess[9] = structPtr->beginAddr & 0x0ff;
    //数量：2字节
    requestMess[10] = structPtr->num >> 8;
    requestMess[11] = structPtr->num & 0x0ff;
    //字节数：1字节
    requestMess[12] = quint8(numOfByte);
    //字节内容
    for(int i = 0; i < numOfByte; i++)
    {
        requestMess[13 + i] = byteArr[i];
    }

    return requestMess;
}

//处理用户线圈输入函数
QByteArray Widget::coilsInputProcess()
{

    //判断字符串是否合法返回值，默认为false
    bool isLegal = false;

    //获取输入框内的字符串,默认为空
    QString writeCoils = nullptr;
    //字符串长度，默认为0
    int writeCoilsLength = 0;
    //初始化对话框
    input = new DataInput;
    input->setModal(true);
    input->hide();

    //发送按钮暂时关闭
    ui->requestBtn->setEnabled(false);

    while((writeCoils.isEmpty())
          || (ui->number->text().toInt() > writeCoilsLength)
          || (!isLegal))
    {

        QString inputDialogTitle = "写多个输出线圈（0/1）";

        QString writeGuide = "请输入" + ui->number->text() + "个线圈：";
        //获取字符串
        input->show();
        writeCoils = input->getData(inputDialogTitle,writeGuide,ui->number->text().toInt(),0);

        //获取字符串长度
        writeCoilsLength = writeCoils.length();
        //判断字符串合法性
        isLegal = coilsValueJudge(writeCoils);

    }

    delete input;
    //发送按钮打开
    ui->requestBtn->setEnabled(true);

    //求出字节数
    int numOfByte = (writeCoilsLength + 7) / 8;

    //对字符串空位进行补0
    for(int i = 1; i <= (8*numOfByte - writeCoilsLength); i++)
    {
        writeCoils += '0';
    }

    //创建线圈输入数组
    QByteArray coilsInputArr;
    coilsInputArr.resize(numOfByte);

    //字节：1字节*numOfByte
    for(int i = 0; i < numOfByte; i++)
    {
        //对8位1字节进行反转处理
        QString vector = writeCoils.mid((8 * i),8);
        //字节反转
        byteReverse(vector);
        //存入请求报文数组
        coilsInputArr[i] = vector.toInt(nullptr,2);
    }

    ByteArrayToString(coilsInputArr,coilsInputArr.size(),1);
    return coilsInputArr;
}

//临时线圈处理
QByteArray Widget::TemporarycoilsProcess(QString data)
{

    int writeCoilsLength = data.length();

    int numOfByte = (writeCoilsLength + 7) / 8;

    //对字符串空位进行补0
    for(int i = 1; i <= (8*numOfByte - writeCoilsLength); i++)
    {
        data += '0';
    }

    //创建线圈输入数组
    QByteArray coilsInputArr;
    coilsInputArr.resize(numOfByte);

    //字节：1字节*numOfByte
    for(int i = 0; i < numOfByte; i++)
    {
        //对8位1字节进行反转处理
        QString vector = data.mid((8 * i),8);
        //字节反转
        byteReverse(vector);
        //存入请求报文数组
        coilsInputArr[i] = vector.toInt(nullptr,2);
    }

    ByteArrayToString(coilsInputArr,coilsInputArr.size(),1);
    return coilsInputArr;

}


// 处理用户寄存器输入函数，返回字节数组
QByteArray Widget::registersInputProcess()
{
    //获取输入寄存器数量
    int num = ui->number->text().toInt();
    //需要的字节数，一个寄存器需要2字节
    int numOfByte = 2*num;
    //创建寄存器输入数组
    QByteArray RegistersInputArr;
    RegistersInputArr.resize(numOfByte);

    //获取输入框内的字符串,默认为空
    QString writeRegister = nullptr;


    //初始化模态对话框

    input = new DataInput;
    input->setModal(true);
    input->hide();

    //输入标题
    QString inputDialogTitle = "写十进制寄存器(0-65535)";
    //输入提示
    QString writeGuide = "请输入" + QString::number(num) + "个寄存器！";
    //获取字符串
    input->show();

    //发送按钮暂时关闭
    ui->requestBtn->setEnabled(false);

    QString writeRegister1 = input->getData(inputDialogTitle,writeGuide,0,num);

    delete input;
    //发送按钮打开
    ui->requestBtn->setEnabled(true);

    for(int res = 0;res<num;res++)
    {

        writeRegister = writeRegister1.section(QRegExp("[/-]"),res+1,res+1);
        qDebug()<<writeRegister;
        //转化为2进制字符串，不足补0，凑足16位
        writeRegister = QString("%1").arg(quint16(writeRegister.toInt(nullptr,10)),16,2,QLatin1Char('0'));
        //前8位为一个字节
        RegistersInputArr[2*res] = writeRegister.mid(0,8).toInt(nullptr,2);
        //后8位为一个字节
        RegistersInputArr[2*res + 1] = writeRegister.mid(8,8).toInt(nullptr,2);
    }

    return RegistersInputArr;
}

//多线圈字符串合法性判断,即值仅为0/1
bool Widget::coilsValueJudge(QString &coils)
{
    QByteArray ba = coils.toLatin1();

    const char *s = ba.data();
    bool bret = true;
    while(*s)
    {
        if(*s != '0' && *s != '1')
        {
            bret = false;
            break;
        }
        s++;
    }

    return bret;
}

//字节反转
void Widget::byteReverse(QString &coils)
{
    // 定义临时字符变量
    QChar temp;

    for(int i=0; i < 4; i++)
    {
        temp = coils[i];        // 将第i个元素存入临时字符变量
        coils[i] = coils[8-i-1];  // 将第i个字符元素和第n-i-1个元素对调
        coils[8-i-1] = temp;    // 将临时字符变量的值赋给第n-i-1个元素
    }
}

//数组转十六进制字符串
//   参数1：目标十六进制数组
//   参数2：需要转化的长度
//   参数3：转化模式，两种模式，默认模式为pattern=0不加空格，pattern=1位加空格
QString Widget::ByteArrayToString(QByteArray HexByteArr,int ConvertLen, int pattern = 0)
{
    //获得目标数组大小
    int HexByteArrSize = HexByteArr.size();
    //判断长度是否合法，如果长度大于数组长度，则设为数组长度，小于0则设置为0
    if(ConvertLen > HexByteArrSize)
    {
        ConvertLen = HexByteArrSize;
    }
    else if(ConvertLen < 0)
    {
        ConvertLen = 0;
    }

    //声明目标字符串
    QString readMes = nullptr;

    for(int i = 0; i < ConvertLen; i++)
    {
        readMes += QString("%1").arg(quint8(HexByteArr.at(i)),2,16,QLatin1Char('0'));
        //判断转换的模式
        if(pattern == 1)
        {
            readMes += " ";
        }
    }

    //返回转化后的十六进制字符串
    return readMes;
}

//TCP主站请求报文发送函数
void Widget::TCPRequestMessageSend()
{
    //判断当前TCP连接状态，如果连接则进行发送，如果断开则不发送，进行提示
    if(TcpConnectIdentifier == true)
    {
        //使用TCP向目标从站传输请求报文
        TCPSocket->write(requestMessageArray);

        //消息框显示发送成功的请求报文
        QString message;
        for(int i = 0; i < requestMessageArray.size(); i++)
        {
            message += QString("%1").arg(quint8(requestMessageArray.at(i)),2,16,QLatin1Char('0'));
            message += " ";
        }

        timeInformationPrint();
        //消息窗口显示信息
        ui->messageEdit->append("请求报文发送成功！ 报文为：" + message);

        //设置TCP请求报文发送状态为在线
        TCPSendIdentifier = true;
    }
    else
    {
        //连接失败，清空请求报文数组，需要重新操作
        requestMessageArray.clear();
        //时间
        timeInformationPrint();
        //消息窗口显示信息
        ui->messageEdit->append("服务器连接断开，请重新操作！");

        //设置TCP请求报文发送状态为离线
        TCPSendIdentifier = false;
    }
}

//报文合法性判断函数
bool Widget::MessageLegalJudge(QByteArray MessageArr, QByteArray requestMessageArr)
{
    bool Result;
    //1. 判断接收到的报文长度是否合法，合法最小长度为写入请求报文的异常响应报文，为9字节
    if(MessageArr.size() < MESSAGE_LENGTH_MIN)
    {
        //消息窗口显示信息
        ui->messageEdit->append("报文长度错误,报文长度小于最小报文长度！");
        return false;
    }
    if(MessageArr.size() > MESSAGE_LENGTH_MAX)
    {
        ui->messageEdit->append("报文长度错误，报文长度大于最大报文长度");
        return false;
    }
    //2. 判断接收到的报文与请求报文的事务元标识符是否一致
    if((MessageArr.at(0) != requestMessageArr.at(0)) || (MessageArr.at(1) != requestMessageArr.at(1)))
    {
        //消息窗口显示信息
        ui->messageEdit->append("事务标识符错误，响应报文与请求报文的事务标识符不一致！");
        return false;
    }

    //3. 判断接收到的报文的协议标识是否是Modbus协议
    if((MessageArr.at(2) != 0) || (MessageArr.at(3) != 0))
    {
        //消息窗口显示信息
        ui->messageEdit->append("协议标识符错误，收到的报文不是Modbus报文！");
        return false;
    }

    //4. 判断接收到的报文的长度的数据与其后的字节长度是否匹配
    if((MessageArr.size() - 6) != BondTwoUint8ToUint16(MessageArr.at(4),MessageArr.at(5)))
    {
        //消息窗口显示信息
        ui->messageEdit->append("报文头中字节字段错误！");
        return false;
    }

    //5. 判断接收到的报文的单元标识符是否与请求报文一致
    if(MessageArr.at(6) != requestMessageArr.at(6))
    {
        //消息窗口显示信息
        ui->messageEdit->append("该报文的发送从站不是请求的从站！");
        return false;
    }

    //6. 判断接收到的报文的功能码是否合法
    Result = FuncCodeLegalJudge(MessageArr);
    if(Result == false)
    {
        return false;
    }

    //7. 处理匹配的异常响应码信息
    Result = ExceptionCodeProcess(MessageArr);
    if(Result == false)
    {
        return false;
    }

    //8. 判断请求与响应的功能码是否一致
    if(MessageArr.at(7) != requestMessageArr.at(7))
    {
        //消息窗口显示信息
        ui->messageEdit->append("收到报文的功能码与请求报文不一致！");
        return false;
    }

    return true;
}

//连接两个quint8数据为一个quint16数据
quint16 Widget::BondTwoUint8ToUint16(quint8 preNum, quint8 afterNum)
{
    quint16 bondNum = (preNum << 8) | afterNum;
    return bondNum;
}

//4. 功能码合法性判断函数
bool Widget::FuncCodeLegalJudge(QByteArray MessageArr)
{
    if(MessageArr.at(7) != 1
            &&MessageArr.at(7) != 3
            &&MessageArr.at(7) != 15
            &&MessageArr.at(7) != 16
            &&quint8(MessageArr.at(7)) != 0x81
            &&quint8(MessageArr.at(7)) != 0x83
            &&quint8(MessageArr.at(7)) != 0x8f
            &&quint8(MessageArr.at(7)) != 0x90)
    {
        //消息窗口显示信息
        ui->messageEdit->append("该报文的功能码无法识别！");
        return false;
    }
    else
    {
        return true;
    }
}

//5. 异常码报文处理函数
bool Widget::ExceptionCodeProcess(QByteArray MessageArr)
{
    QString exceptionPrompt;
    //处理匹配的异常响应码信息
    switch (quint8(MessageArr.at(7)))
    {
    case 0x81:
    {
        exceptionPrompt = "读多个线圈的请求报文出现异常！";
        break;
    }
    case 0x83:
    {
        exceptionPrompt = "读多个寄存器的请求报文出现异常！";
        break;
    }
    case 0x8f:
    {
        exceptionPrompt = "写入多个线圈的请求报文出现异常！";
        break;
    }
    case 0x90:
    {
        exceptionPrompt = "写入多个寄存器的请求报文出现异常！";
        break;
    }
    default:
    {
        return true;
    }
    }

    //获取异常码
    quint8 exceptionCode = quint8(MessageArr.at(8));

    ui->messageEdit->append(exceptionPrompt);

    //异常码判断
    ExceptionCodeJudge(exceptionCode);

    return false;
}

//异常码判断函数
void Widget::ExceptionCodeJudge(quint8 excCode)
{
    QString exceptionCodePrompt;
    switch (excCode)
    {
    case 0x01:
    {
        exceptionCodePrompt = "异常码为：01 非法功能";
        break;
    }
    case 0x02:
    {
        exceptionCodePrompt = "异常码为：02 非法数据地址";
        break;
    }
    case 0x03:
    {
        exceptionCodePrompt = "异常码为：03 非法数据值";
        break;
    }
    }
    //消息窗口显示信息
    ui->messageEdit->append(exceptionCodePrompt);

    return;
}

//0X01功能码报文处理函数
bool Widget::FuncCodeProcess0X01(QByteArray MessageArr, QByteArray requestMessageArr)
{
    //处理匹配的正常响应码
    QString dataObtained;
    quint8 numOfByte;
    quint16 length;

    //判断响应报文的长度是否符合最低要求
    if(MessageArr.size() < 10)
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文的长度异常！");
        return false;
    }

    //先判断响应报文的字节数是否和请求报文需要的对应
    //求出请求报文中想读的线圈数量number
    quint16 number = BondTwoUint8ToUint16(quint8(requestMessageArr.at(10)),quint8(requestMessageArr.at(11)));

    //判断响应报文的字节数是否和满足number需要的字节数匹配
    //求出字节数
    numOfByte = (number + 7) / 8;

    //如果响应报文的字节数和满足number需要的字节数不匹配，则显示错误信息
    if(numOfByte != quint8(MessageArr.at(8)))
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文的字节数异常！");
        return false;
    }

    //判断自身长度字段是否异常
    length =quint16(BondTwoUint8ToUint16(MessageArr.at(4),MessageArr.at(5)));
    //如果不匹配，则输出错误信息
    if(length != MessageArr.size() - 6)
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文自身的长度字段异常！");
        return false;
    }

    //判断自身字节数字段是否异常
    if((quint8)MessageArr.at(8) != (MessageArr.size() - 9))
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文自身的字节数字段异常！");
        return false;
    }

    //取出所读的多个线圈，并显示，数据从第九位开始
    for(int i = 0; i < quint8(MessageArr.at(8)); i++)
    {
        //先转化为2进制字符串
        QString str = QString::number(quint8(MessageArr.at(9 + i)),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg(quint8(str.toInt(nullptr,2)),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        dataObtained += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    dataObtained = dataObtained.left(number);

    quint16 BeginAddress;
    BeginAddress = BondTwoUint8ToUint16(quint8(requestMessageArr[8]),quint8(requestMessageArr[9]));
    quint16 DataNumber;
    DataNumber = BondTwoUint8ToUint16(quint8(requestMessageArr[10]),quint8(requestMessageArr[11]));

    UpdateCoilsData(BeginAddress,DataNumber,dataObtained);

    //提示响应报文解析成功
    //时间
    timeInformationPrint();
    //消息窗口显示信息
    ui->messageEdit->append("多线圈读取成功!");
    ui->messageEdit->append("成功读取到来自IP地址："
                            + IPAddr
                            + " 端口号："
                            + QString::number(port)
                            + "的"
                            + ui->number->text()
                            + "个线圈：");
    ui->messageEdit->append(dataObtained);

    return true;
}

//0X03功能码报文处理函数
bool Widget::FuncCodeProcess0X03(QByteArray MessageArr, QByteArray requestMessageArr)
{
    //处理匹配的正常响应码
    QString dataObtained;
    quint16 length;

    //判断响应报文的长度是否符合最低要求
    if(MessageArr.size() < 10)
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文的长度异常！");
        return false;
    }

    //先判断响应报文的字节数是否和请求报文需要的对应
    //求出请求报文中想读的寄存器数量number
    quint16 number = BondTwoUint8ToUint16(quint8(requestMessageArr.at(10)),quint8(requestMessageArr.at(11)));

    //如果响应报文的字节数和满足number需要的字节数不匹配，则显示错误信息
    if(2*number != quint8(MessageArr.at(8)))
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文的字节数异常！");
        return false;
    }

    //判断自身长度字段是否异常
    length =quint16(BondTwoUint8ToUint16(MessageArr.at(4),MessageArr.at(5)));
    //如果不匹配，则输出错误信息
    if(length != MessageArr.size() - 6)
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文自身的长度字段异常！");
        return false;
    }

    //判断自身字节数字段是否异常
    if(quint8(MessageArr.at(8)) != (MessageArr.size() - 9))
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文自身的字节数字段异常！");
        return false;
    }

    //取出所读的多个寄存器，并显示，数据从第9个字节开始
    for(int i = 0; i < quint8(MessageArr.at(8)); i += 2)
    {
        dataObtained += QString::number(BondTwoUint8ToUint16(quint8(MessageArr.at(9 + i)),quint8(MessageArr.at(10 + i))));
        dataObtained += " ";
    }

    //写入查询数据
    quint16 BeginAddress;
    BeginAddress = BondTwoUint8ToUint16(quint8(requestMessageArr[8]),quint8(requestMessageArr[9]));
    quint16 DataNumber;
    DataNumber = BondTwoUint8ToUint16(quint8(requestMessageArr[10]),quint8(requestMessageArr[11]));
    UpdateRegistersData(BeginAddress,DataNumber,dataObtained);

    //提示响应报文解析成功
    //时间
    timeInformationPrint();
    //消息窗口显示信息
    ui->messageEdit->append("多寄存器读取成功!");
    ui->messageEdit->append("成功读取到来自IP地址："
                            + IPAddr
                            + " 端口号："
                            + QString::number(port)
                            + "的"
                            + ui->number->text()
                            + "个寄存器：");
    ui->messageEdit->append(dataObtained);

    return true;
}

//0X0f功能码报文处理函数
bool Widget::FuncCodeProcess0X0F(QByteArray MessageArr, QByteArray requestMessageArr)
{
    //处理匹配的正常响应码
    quint16 messageArrayBeginAddress;
    quint16 requestMessageBegainAddress;
    quint16 length;
    quint16 messageArrayByteNum;
    quint16 requestMessageByteNum;

    //判断响应报文的长度是否符合最低要求，写入请求报文的响应报文为固定长度12
    if(MessageArr.size() != 12)
    {
        //时间
        timeInformationPrint();
        //消息窗口显示信息
        ui->messageEdit->append("响应报文的长度异常！");
        return false;
    }

    //判断自身长度字段是否异常
    length =quint16(BondTwoUint8ToUint16(MessageArr.at(4),MessageArr.at(5)));
    //如果不匹配，则输出错误信息
    if(length != 6)
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文自身的长度字段异常！");
        return false;
    }

    //判断收到的报文的起始地址字段是否与请求报文匹配
    messageArrayBeginAddress = quint16(BondTwoUint8ToUint16(MessageArr.at(8),MessageArr.at(9)));
    requestMessageBegainAddress = quint16(BondTwoUint8ToUint16(requestMessageArr.at(8),requestMessageArr.at(9)));
    if(messageArrayBeginAddress != requestMessageBegainAddress)
    {
        //消息窗口显示信息
        ui->messageEdit->append("收到的报文的起始地址字段与请求报文不匹配！");
        return false;
    }

    //判断收到的报文的数量字段是否与请求报文匹配
    messageArrayByteNum = quint16(BondTwoUint8ToUint16(MessageArr.at(10),MessageArr.at(11)));
    requestMessageByteNum = quint16(BondTwoUint8ToUint16(requestMessageArr.at(10),requestMessageArr.at(11)));
    if(messageArrayByteNum != requestMessageByteNum)
    {
        //消息窗口显示信息
        ui->messageEdit->append("收到的报文的数量字段与请求报文不匹配！");
        return false;
    }

    //提示响应报文解析成功
    //时间
    timeInformationPrint();
    //消息窗口显示信息
    ui->messageEdit->append("多线圈写入成功!");
    ui->messageEdit->append("成功向IP地址:"
                            + IPAddr
                            + " 端口号："
                            + QString::number(port)
                            + "起始位置："
                            + ui->startAddr->text()
                            + "处写入"
                            + ui->number->text()
                            + "个线圈！");

    return true;
}

//0X10功能码报文处理函数
bool Widget::FuncCodeProcess0X10(QByteArray MessageArr, QByteArray requestMessageArr)
{
    //处理匹配的正常响应码
    quint16 messageArrayBeginAddress;
    quint16 requestMessageBegainAddress;
    quint16 length;
    quint16 messageArrayByteNum;
    quint16 requestMessageByteNum;

    //判断响应报文的长度是否符合最低要求，写入请求报文的响应报文为固定长度12
    if(MessageArr.size() != 12)
    {
        //时间
        timeInformationPrint();
        //消息窗口显示信息
        ui->messageEdit->append("响应报文的长度异常！");
        return false;
    }

    //判断自身长度字段是否异常
    length =quint16(BondTwoUint8ToUint16(MessageArr.at(4),MessageArr.at(5)));
    //如果不匹配，则输出错误信息
    if(length != 6)
    {
        //消息窗口显示信息
        ui->messageEdit->append("响应报文自身的长度字段异常！");
        return false;
    }

    //判断收到的报文的起始地址字段是否与请求报文匹配
    messageArrayBeginAddress = quint16(BondTwoUint8ToUint16(MessageArr.at(8),MessageArr.at(9)));
    requestMessageBegainAddress = quint16(BondTwoUint8ToUint16(requestMessageArr.at(8),requestMessageArr.at(9)));
    if(messageArrayBeginAddress != requestMessageBegainAddress)
    {
        //消息窗口显示信息
        ui->messageEdit->append("收到的报文的起始地址字段与请求报文不匹配！");
        return false;
    }

    //判断收到的报文的数量字段是否与请求报文匹配
    messageArrayByteNum = quint16(BondTwoUint8ToUint16(MessageArr.at(10),MessageArr.at(11)));
    requestMessageByteNum = quint16(BondTwoUint8ToUint16(requestMessageArr.at(10),requestMessageArr.at(11)));
    if(messageArrayByteNum != requestMessageByteNum)
    {
        //消息窗口显示信息
        ui->messageEdit->append("收到的报文的数量字段与请求报文不匹配！");

        return false;
    }

    //提示响应报文解析成功
    //时间
    timeInformationPrint();
    //消息窗口显示信息
    ui->messageEdit->append("多寄存器写入成功!");
    ui->messageEdit->append("成功向IP地址:"
                            + IPAddr
                            + " 端口号："
                            + QString::number(port)
                            + "起始位置："
                            + ui->startAddr->text()
                            + "处写入"
                            + ui->number->text()
                            + "个寄存器！");

    return true;
}

//更新线圈
void Widget::UpdateCoilsData(quint16 BeginAddress,quint16 DataNumber,QString DataString)
{
    //锁住写入线圈数据信号，进行阻塞
    ui->coilTable->blockSignals(true);
    for(int i=0;i<DataNumber;i++)
    {
        int Column = BeginAddress + i;
        QString coilData = DataString.at(i);
        WriteCoilsData(Column,coilData);
    }
    //解锁写入线圈数据信号
    ui->coilTable->blockSignals(false);
}
//写线圈
void Widget::WriteCoilsData(int Column, QString CoilData)
{

    //更新ini文件数据
    settings->setValue("Section" + QString::number(Column + 1) + "/coil",CoilData);
    //更新线圈数据表中数据
    if(CoilData == "1")
    {
        CoilData = "ON";
    }
    else
    {
        CoilData = "OFF";
    }
    ui->coilTable->setItem(1,Column,new QTableWidgetItem(CoilData));
    //设置表格内文字水平+垂直对齐
    ui->coilTable->item(1,Column)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
}

//更新寄存器
void Widget::UpdateRegistersData(quint16 BeginAddress, quint16 DataNumber, QString DataString)
{
    //锁住写入寄存器数据信号，进行阻塞
    ui->registerTable->blockSignals(true);
    //写入寄存器
    QString temp;
    int j=0;
    for(int i=0;i<DataNumber;i++)
    {
        while(j< DataString.size() && DataString[j] != ' ')
        {
            temp +=DataString[j];
            j++;
        }
        WriteRegistersData(BeginAddress+i,temp);
        temp.clear();
        j++;
    }
    //解锁写入寄存器数据信号
    ui->registerTable->blockSignals(false);
}
//写寄存器
void Widget::WriteRegistersData(int Column, QString registerData)
{
    //更新ini文件数据
    settings->setValue("Section" + QString::number(Column + 1) + "/regi",registerData);
    //更新线圈数据表中数据
    ui->registerTable->setItem(1,Column,new QTableWidgetItem(registerData));
    //设置表格内文字水平+垂直对齐
    ui->registerTable->item(1,Column)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
}
